﻿// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
// Website: https://admin.blazor.zone

using BlazorAdmin.Caching;
using BlazorAdmin.Extensions;
using BlazorAdmin.Models;
using BlazorAdmin.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using BlazorAdmin.Services.DbService;

namespace BlazorAdmin.Services
{
    /// <summary>
    /// 
    /// </summary>
    internal class NavigationService : BaMgmtDbService, INavigation
    {
        private const string NavigationServiceGetAllCacheKey = "NavigationService-GetAll";
        private const string NavigationServiceGetMenusByRoleIdCacheKey = "NavigationService-GetMenusByRoleId";
        /// <summary>
        /// 
        /// </summary>
        /// <param name="db"></param>
        public NavigationService(IPetaPoco db) : base(db)
        {
        }

        /// <summary>
        /// 获得指定用户名可访问的所有菜单集合
        /// </summary>
        /// <param name="userName">当前用户名</param>
        /// <returns>未层次化的菜单集合</returns>
        public List<Navigation> GetAllMenus(string userName) => CacheManager.GetOrAdd($"{NavigationServiceGetAllCacheKey}-{userName}", entry =>
        {
            const string sql = @"SELECT n.ID, n.ParentID, n.Name, n.SortNo, n.Icon, n.Url, n.Category, n.Target, n.IsResource, n.Application 
                                 FROM Navigations n INNER JOIN (
	                                 SELECT nr.NavigationID FROM Users u 
	                                 INNER JOIN UserRole ur ON ur.UserID = u.ID 
	                                 INNER JOIN NavigationRole nr ON nr.RoleID = ur.RoleID 
	                                 WHERE u.UserName = @UserName 
	                                 UNION 
	                                 SELECT nr.NavigationID FROM Users u INNER JOIN UserGroup ug ON u.ID = ug.UserID 
	                                 INNER JOIN RoleGroup rg ON rg.GroupID = ug.GroupID INNER JOIN NavigationRole nr 
	                                 ON nr.RoleID = rg.RoleID WHERE u.UserName = @UserName 
	                                 UNION SELECT n.ID FROM Navigations n 
	                                 WHERE EXISTS (SELECT UserName FROM Users u INNER JOIN UserRole ur ON u.ID = ur.UserID 
	                                 INNER JOIN Roles r ON ur.RoleID = r.ID WHERE u.UserName = @UserName AND r.RoleName = @RoleName)
                                 ) nav ON n.ID = nav.NavigationID ORDER BY n.Application, n.SortNo";
            return Fetch<Navigation>(sql, new { UserName = userName, RoleName = "Administrators" });
        });

        /// <summary>
        /// 
        /// </summary>
        /// <param name="roleId"></param>
        /// <returns></returns>
        public List<int> GetMenusByRoleId(int roleId) => CacheManager.GetOrAdd($"{NavigationServiceGetMenusByRoleIdCacheKey}-{roleId}",
            entry => Fetch<int>("SELECT NavigationID FROM NavigationRole WHERE RoleID = @0", roleId));

        /// <summary>
        /// 
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="menuIds"></param>
        /// <returns></returns>
        public bool SaveMenusByRoleId(int roleId, List<string> menuIds)
        {
            var ret = false;
            IEnumerable<int> ids = from id in menuIds where int.TryParse(id, out int tid) select int.Parse(id);
            using var db = Create();
            try
            {
                db.BeginTransaction();
                db.Execute("DELETE FROM NavigationRole WHERE RoleID = @0", roleId);
                db.InsertBatch("NavigationRole", ids.Select(g => new { NavigationID = g, RoleID = roleId }));
                db.CompleteTransaction();
                ret = true;
            }
            catch (Exception)
            {
                db.AbortTransaction();
                throw;
            }
            if (ret)
            {
                CacheManager.Clear();
            }
            return ret;
        }
    }
}